對於寫 JS 的朋友,我想這主題算是 最熟悉的陌生人,對於新手來說這是必懂的主題,對於資深的人來說可能在這上面踩過不少雷,但你真的懂嗎 ? 到底什麼是 this ?
定義上:
this 這個關鍵字代表的值為目前執行環境的 ThisBinding
在大多數情況下,this 會因為 function 呼叫的方式而有所不同
So, this 到底是什麼? 看著定義我沈默 3 秒,最好看的懂拉 ....
在開始說 this 前,我們先說說 Context(上下文):
Context 指的是函式在被
呼叫執行時,所處的物件環境。
Context 決定了 JS 執行過程中可以獲取哪些變量、數據、函數,每一個 Context 都會綁定一個變量對象(Variable Object),它用來儲存 Context 所有已經定義的變量,函數。
Context   vs  Scope(作用域):
Scope 指的是在函式中變數的可使用範圍,在函式定義的時候就已經決定了。
所以 this 表示的其實是 函數調用的上下文 (context) ,而 context 默認是全局 window。
console.log(this);   // this 等於 ECMAScript 在瀏覽器環境的 global對象,window
function bar() {
    'use strict'
    console.log(this);
}
bar()  // undefined
默認綁定作用於函數直接調用,此時 this 會指向全局 window,但嚴格模式會指向 undefined
function getName() {
    console.log(this.name);
}
var meggie = {
    name: 'Meggie';
}
var jacky = {
    name: 'Jacky';
}
getName.apply(meggie); //'Meggie'
getName.apply(jacky); // 'Jacky'
顯示綁定的優點?
可以明確的指定要執行 function 中的 this 是什麼,不需要透過另一個變數來暫存 this 的方式來獲取,這方法也往往更直觀,不像 callback function 會改變指向。
其實 隱式綁定都只是語法糖,都可以寫成 apply,bind,call 的方式,apply,bind,call 雖然麻煩但往往更正規。
Call vs Apply vs Bind:
function.call (thisArg, arg1, arg2, ...)function.apply (thisArg, [argsArray])
都是將 this 以及 parameters 傳入,重新定義 this 指向,而且會立刻執行前面的 function
func.bind (thisArg[, arg1[, arg2[, ...]]])
是借用舊有的函數來建立一個新的函數,並且將 this 綁定到物件中,不會立刻執行前面的 function
Bind 函數存在著多次綁定的問題,如果多次綁定this,則以第一次為主
var obj = {
    id: 10,
    getId: function() {
        console.log(this.id);
    }
}
obj.getId() // this 為 object
隱式綁定作用於函數,首先查看是不是有Context 的對象,如果有那麼this會綁定到這個對象上。
隱式綁定丟失 this 的問題:
const obj = {
  foo: function() {
    console.log(this);
  }
}
obj.foo();  // obj
setTimeout(obj.foo, 0);  // window
// 解決辦法:setTimeout(obj.foo.bind(obj), 0) // obj
setTimeout(function() {
  obj.foo();  // obj
},10);
為什麼作為 obj.foo() 的時候就沒問題,而 callback this卻丟失了呢? 因為 obj.foo 本身屬於匿名函數,這其實是一個函數上直接的調用,所以應用了 默認綁定,導致 this 丟失。
const obj = {
  a: function () {
    console.log(this) // obj
    function a1() {
      console.log(this) // window
    }
    // 解決辦法,改用箭頭函數 var a1 = () => { console.log(this); }
    a1()
  }
}
obj.a()
所以來考考大家,為什麼執行 a1() 的時候返回的是 window 的 this 呢?
因為這邊的 a1() 也是屬於函數直接調用,所以為 window
function User() {}
User.prototype.getId = function() {
    console.log(this.id);
}
var user = new User();
user.id = 10;
user.getId() // 10,因為 this 指向 User
new在創建實例(instance)的時候事實上是對新實例 this 不斷地賦值,將 __proto__ 指向原型。
this 值,它繼承外面作用域的 this
以下這個例子,因為 ES6 是嚴格模式,嚴格模式下的全域作用域為 undefind,所以 this 為 undefined:
const foo = (options) => {
  console.log(this); // undefined
};
this 的值到底是什么?一次说清楚
JS 紀錄7 - this 指向判斷的方式
this綁定的四種方法